home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / Apple Guide / Engineering / APISample / APISampleCW / Source / TApplication.cp next >
Encoding:
Text File  |  1994-06-01  |  16.7 KB  |  564 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple Application Framework
  6. #
  7. #    TApplication
  8. #
  9. #    TApplication.cp        -    C++ source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.20                    10/91
  16. #            1.10                     07/89
  17. #            1.00                     04/89
  18. #
  19. #    Components:
  20. #            TApplicationCommon.h    July 9, 1989
  21. #            TApplication.h            July 9, 1989
  22. #            TApplication.cp            July 9, 1989
  23. #            TApplication.r            July 9, 1989
  24. #            TDocument.h                July 9, 1989
  25. #
  26. #    TApplication is a rudimentary application framework
  27. #    for C++. The applications CPlusShapesApp and CPlusTESample
  28. #    are built using CPlusAppLib.
  29. #
  30. ------------------------------------------------------------------------------*/
  31.  
  32.  
  33. /*
  34. Segmentation strategy:
  35.  
  36.     This program has only one segment, since the issues
  37.     surrounding segmentation within a class's methods have
  38.     not been investigated yet. We DO unload the data
  39.     initialization segment at startup time, which frees up
  40.     some memory 
  41.  
  42. SetPort strategy:
  43.  
  44.     Toolbox routines do not change the current port. In
  45.     spite of this, in this program we use a strategy of
  46.     calling SetPort whenever we want to draw or make calls
  47.     which depend on the current port. This makes us less
  48.     vulnerable to bugs in other software which might alter
  49.     the current port (such as the bug (feature?) in many
  50.     desk accessories which change the port on OpenDeskAcc).
  51.     Hopefully, this also makes the routines from this
  52.     program more self-contained, since they don't depend on
  53.     the current port setting. 
  54.  
  55. Clipboard strategy:
  56.  
  57.     This program does not maintain a private scrap.
  58.     Whenever a cut, copy, or paste occurs, we import/export
  59.     from the public scrap to TextEdit's scrap right away,
  60.     using the TEToScrap and TEFromScrap routines. If we did
  61.     use a private scrap, the import/export would be in the
  62.     activate/deactivate event and suspend/resume event
  63.     routines. 
  64. */
  65.  
  66. // Mac Includes
  67. #include <Types.h>
  68. #include <QuickDraw.h>
  69. #include <Fonts.h>
  70. #include <Events.h>
  71. #include <Controls.h>
  72. #include <Windows.h>
  73. #include <Menus.h>
  74. #include <TextEdit.h>
  75. #include <Dialogs.h>
  76. #include <Desk.h>
  77. #include <Scrap.h>
  78. #include <ToolUtils.h>
  79. #include <Memory.h>
  80. #include <SegLoad.h>
  81. #include <Files.h>
  82. #include <OSUtils.h>
  83. #include <Traps.h>
  84.  
  85. #include "TApplication.h"                    // use the local version. If you make changes
  86.                                             // that you've debugged and want other files
  87.                                             // to use, simple copy this header file into
  88.                                             // the C++ Includes folder (don't forget to
  89.                                             // copy the TApplication object library to the C++
  90.                                             // Libraries folder)!
  91.  
  92. #ifndef __UAPPSHARED__
  93.     #include "UAppShared.h"
  94. #endif
  95.  
  96. // OSEvent is the event number of the suspend/resume and mouse-moved events sent
  97. // by MultiFinder. Once we determine that an event is an osEvent, we look at the
  98. // high byte of the message sent to determine which kind it is. To differentiate
  99. // suspend and resume events we check the resumeMask bit.
  100. const short kOsEvent = app4Evt;                // event used by MultiFinder
  101. const short kSuspendResumeMessage = 0x01;    // high byte of suspend/resume event message
  102. const short kClipConvertMask = 0x02;        // bit of message field clip conversion
  103. const short kResumeMask = 0x01;                // bit of message field for resume vs. suspend
  104. const short kMouseMovedMessage = 0xFA;        // high byte of mouse-moved event message
  105.  
  106. extern "C"
  107.     // from MPW standard library
  108.         void _DataInit(void);                // sets up A5 globals
  109. };
  110.  
  111. /***********************************************************************/
  112. //
  113. // TApplication class declarations
  114. //
  115. /***********************************************************************/
  116.  
  117. //-----------------------------------------------------------------------
  118. // TApplication::TApplication -     
  119. //
  120.     TApplication::TApplication( void )
  121.     {
  122.         SysEnvRec envRec;
  123.         long stkNeeded, heapSize;
  124.     
  125.         // initialize Mac Toolbox components
  126.             InitGraf((Ptr) &qd.thePort );
  127.             InitFonts();
  128.             InitWindows();
  129.             InitMenus();
  130.             TEInit();
  131.             InitDialogs(nil);
  132.             InitCursor();
  133.     
  134.         // ignore the error returned from SysEnvirons; even if an error occurred,
  135.         // the SysEnvirons glue will fill in the SysEnvRec
  136.             ( void ) SysEnvirons( curSysEnvVers, &envRec );
  137.     
  138.         // Are we running on a 128K ROM machine or better???
  139.             if ( envRec.machineType < 0 )
  140.                 BigBadError( kErrStrings,eWrongMachine );        // if not, alert & quit
  141.     
  142.         // if we need more stack space, get it now
  143.             stkNeeded = StackNeeded();
  144.             if (stkNeeded > StackSpace())
  145.             {
  146.                 // new address is heap size + current stack - needed stack
  147.                     SetApplLimit((Ptr) ((long) GetApplLimit() - stkNeeded + StackSpace()));
  148.             }
  149.     
  150.         // Check for minimum heap size
  151.             heapSize = (long) GetApplLimit() - (long) ApplicZone();
  152.             if ( heapSize < HeapNeeded())
  153.                 BigBadError( kErrStrings, eSmallSize );
  154.     
  155.         // expand the heap so new code segments load at the top
  156.             MaxApplZone();
  157.     
  158.         // allocate an empty document list
  159.             fDocList = new TDocumentList;
  160.     
  161.         // check to see if WaitNextEvent is implemented
  162.             fHaveWaitNextEvent = TrapAvailable( _WaitNextEvent);
  163.     
  164.         // initialize our class variables
  165.             fCurDoc = nil;
  166.             fDone = false;
  167.             fInBackground = false;
  168.             fMouseRgn = nil;
  169.             fWhichWindow = nil;
  170.             
  171.     } /* TApplication (constructor) */
  172.  
  173.  
  174. //-----------------------------------------------------------------------
  175. // TApplication::ExitLoop -     we're quitting the application; let's
  176. //                                do whatever needs to be done to clean up.
  177. //                                In our case, there isn't much to be done.
  178. //
  179.     void TApplication::ExitLoop( void )
  180.     {
  181.         fDone = true;
  182.     }
  183.  
  184.  
  185. //-----------------------------------------------------------------------
  186. // TApplication::EventLoop -     keep track of events and handle them
  187. //                                appropriately.
  188. //
  189.     void TApplication::EventLoop( void )
  190.     {
  191.         int gotEvent;
  192.         EventRecord tEvt;
  193.     
  194.         SetUp();                    // call setup routine
  195.         DoIdle();                    // do idle once
  196.     
  197.         while (fDone == false)
  198.           {
  199.             // always set up fWhichWindow before doing anything
  200.                 fWhichWindow = FrontWindow();
  201.                 
  202.             // see if window belongs to a document
  203.                 fCurDoc = fDocList->FindDoc(fWhichWindow);
  204.                 
  205.             // make sure we always draw into correct window
  206.                 SetPort(fWhichWindow);
  207.     
  208.             // let's allow others to use the cpu if they need (Multifinder friendliness).
  209.                 DoIdle();            // call idle time handler. this lets apps blink the caret
  210.                                     // or whatever else they wish to do
  211.             
  212.             //     determine if an event has occurred and what to do about it
  213.                 if ( fHaveWaitNextEvent )
  214.                 {
  215.                     gotEvent = WaitNextEvent( everyEvent, &tEvt, SleepVal(), fMouseRgn );
  216.                 }
  217.                 else
  218.                 {
  219.                     SystemTask();
  220.                     gotEvent = GetNextEvent( everyEvent, &tEvt );
  221.                 }
  222.                 fTheEvent = tEvt;
  223.     
  224.             // make sure we got a real event
  225.                 if ( gotEvent )
  226.                 {
  227.                     AdjustCursor();
  228.                     switch (fTheEvent.what)
  229.                     {
  230.                         case mouseDown :    DoMouseDown();
  231.                                             break;
  232.                                             
  233.                         case mouseUp :        DoMouseUp();
  234.                                             break;
  235.                                             
  236.                         case keyDown :
  237.                         case autoKey :        DoKeyDown();
  238.                                             break;
  239.                                             
  240.                         case updateEvt :    DoUpdateEvt();                
  241.                                             break;
  242.                                             
  243.                         case diskEvt :        DoDiskEvt();
  244.                                             break;
  245.                                             
  246.                         case activateEvt :    DoActivateEvt();
  247.                                             break;
  248.                                             
  249.                         case kOsEvent :        DoOSEvent();
  250.                                             break;
  251.                                             
  252.                         default :            break;
  253.                         
  254.                     } // end switch (fTheEvent.what)
  255.                 }
  256.                 
  257.             // update the cursor shape as needed after the event
  258.                 AdjustCursor();
  259.         }
  260.         // call cleanup handler
  261.         CleanUp();
  262.         
  263.     }  /* TApplication::EventLoop */
  264.  
  265.  
  266. //-----------------------------------------------------------------------
  267. // TApplication::DoKeyDown -     simple routine to handle key presses.
  268. //
  269.     void TApplication::DoKeyDown( void )
  270.     {
  271.         char key;
  272.         long mResult;
  273.     
  274.         key = (char) ( fTheEvent.message & charCodeMask );
  275.         if (( fTheEvent.modifiers & cmdKey ) && ( fTheEvent.what == keyDown ))
  276.         {
  277.             // only do command keys if we are not autokeying
  278.                 AdjustMenus();                    // make sure menus are up to date
  279.                 mResult = MenuKey( key );
  280.                 if ( mResult != 0 )                // if it wasn't a menu key, pass it through
  281.                 {
  282.                     DoMenuCommand( HiWrd( mResult ), LoWrd( mResult ));
  283.                     return;
  284.                 }
  285.         }
  286.         
  287.         if ( fCurDoc != nil )
  288.         {
  289.             EventRecord tEvt;
  290.     
  291.             // we copy event record so that we don't pass reference to object field 
  292.             tEvt = fTheEvent;
  293.             fCurDoc->DoKeyDown( &tEvt );
  294.         }
  295.           
  296.     }  /* TApplication::DoKeyDown */
  297.  
  298.  
  299. //-----------------------------------------------------------------------
  300. // TApplication::DoActivateEvt -     a window is becoming active. if it is
  301. //                                    one of ours, call the document's activate
  302. //                                    routine.
  303. //
  304.     void TApplication::DoActivateEvt( void )
  305.     {
  306.         // event record contains window ptr
  307.             fWhichWindow = (WindowPtr) fTheEvent.message;
  308.  
  309.         // see if window belongs to a document
  310.             fCurDoc = fDocList->FindDoc( fWhichWindow );
  311.             SetPort( fWhichWindow );
  312.     
  313.         if ( fCurDoc != nil )
  314.           fCurDoc->DoActivate(( fTheEvent.modifiers & activeFlag ) != 0 );
  315.     
  316.     }  /* TApplication::DoActivateEvt */
  317.  
  318.  
  319. //-----------------------------------------------------------------------
  320. // TApplication::DoUpdateEvt -     a window needs to be updated. If it is one
  321. //                                of ours, call the document's update routine
  322. //                                to redraw it.
  323. //
  324.     void TApplication::DoUpdateEvt(void)
  325.     {
  326.         // event record contains window ptr
  327.             fWhichWindow = (WindowPtr) fTheEvent.message;
  328.  
  329.         // see if window belongs to a document
  330.             fCurDoc = fDocList->FindDoc( fWhichWindow );
  331.             SetPort( fWhichWindow );
  332.         
  333.             if ( fCurDoc != nil )
  334.                 fCurDoc->DoUpdate();
  335.           
  336.     }  /* TApplication::DoUpdateEvt */
  337.  
  338.  
  339. //-----------------------------------------------------------------------
  340. // TApplication::DoSuspend -     although our suspend and resume routine are
  341. //                                identical, let's use two distinct routines
  342. //                                so that a subclass can choose to override one
  343. //                                without having to rewrite the other.
  344. //
  345.     void TApplication::DoSuspend( Boolean doClipConvert )
  346.     {
  347.         doClipConvert = false;        // this is here because I HATE compiler warnings!!
  348.         if (fCurDoc != nil)
  349.           fCurDoc->DoActivate( !fInBackground );
  350.           
  351.     }  /* TApplication::DoSuspend */
  352.  
  353.  
  354. //-----------------------------------------------------------------------
  355. // TApplication::DoResume -     although our suspend and resume routine are
  356. //                                identical, let's use two distinct routines
  357. //                                so that a subclass can choose to override one
  358. //                                without having to rewrite the other.
  359. //
  360.     void TApplication::DoResume( Boolean doClipConvert )
  361.     {
  362.         doClipConvert = false;        // this is here because I HATE compiler warnings!!
  363.         if ( fCurDoc != nil )
  364.           fCurDoc->DoActivate( !fInBackground );
  365.           
  366.     }  /* TApplication::DoResume */
  367.  
  368.  
  369. //-----------------------------------------------------------------------
  370. // TApplication::DoOSEvent -     handle multifinder events accordingly.
  371. //
  372.     void TApplication::DoOSEvent(void)
  373.     {
  374.         Boolean doConvert;
  375.         unsigned char evType;
  376.     
  377.         // is it a multifinder event?
  378.             evType = (unsigned char) (fTheEvent.message >> 24) & 0x00ff;
  379.             switch ( evType )                    // high byte of message is type of event
  380.             {                                     
  381.                 case kMouseMovedMessage :        DoIdle();                    // mouse-moved is also an idle event
  382.                                                 break;
  383.                     
  384.                 case kSuspendResumeMessage :    doConvert = ( fTheEvent.message & kClipConvertMask ) != 0;
  385.                                                 fInBackground = ( fTheEvent.message & kResumeMask ) == 0;
  386.                                                 
  387.                                                 // depending on whether or not we're in the background call suspend or resume
  388.                                                     if ( fInBackground )
  389.                                                         DoSuspend( doConvert );
  390.                                                     else
  391.                                                         DoResume( doConvert );
  392.                                                 
  393.                                                 break;
  394.             }
  395.         
  396.     }  /* TApplication::DoOSEvent */
  397.  
  398.  
  399. //-----------------------------------------------------------------------
  400. // TApplication::DoMouseDown -     simple routine to handle a mouse click.
  401. //
  402.     void TApplication::DoMouseDown( void )
  403.     {
  404.         long        mResult;
  405.         short        partCode;
  406.         WindowPtr    tWind;
  407.         EventRecord    tEvt;
  408.     
  409.         // gotta watch those object field dereferences
  410.             partCode = FindWindow( fTheEvent.where, &tWind );
  411.             fWhichWindow = tWind;
  412.             tEvt = fTheEvent;
  413.             switch ( partCode )
  414.             {
  415.                 case inSysWindow :    DoMouseInSysWindow();
  416.                                     break;
  417.                                     
  418.                 case inMenuBar :    AdjustMenus();
  419.                                     mResult = MenuSelect( tEvt.where );
  420.                                     if ( mResult != 0 )
  421.                                       DoMenuCommand(HiWrd( mResult ), LoWrd( mResult ));
  422.                                     break;
  423.                                     
  424.                 case inGoAway :        DoGoAway();                    
  425.                                     break;
  426.                                     
  427.                 case inDrag :        DoDrag();
  428.                                     break;
  429.                                     
  430.                 case inGrow :        if ( fCurDoc != nil )
  431.                                           fCurDoc->DoGrow( &tEvt );                    
  432.                                     break;
  433.                 case inZoomIn :
  434.                 case inZoomOut :    if (( TrackBox(fWhichWindow, tEvt.where, partCode )) && ( fCurDoc != nil ))
  435.                                         fCurDoc->DoZoom(partCode);
  436.                                     break;
  437.                                     
  438.                 case inContent :    // If window is not in front, make it so
  439.                                         if ( fWhichWindow != FrontWindow() )
  440.                                             SelectWindow(fWhichWindow);
  441.                                         else
  442.                                             if (fCurDoc != nil)
  443.                                                  fCurDoc->DoContent(&tEvt);                    
  444.                                     break;
  445.             }
  446.           
  447.     }  /* TApplication::DoMouseDown */
  448.  
  449.  
  450. //-----------------------------------------------------------------------
  451. // TApplication::DoDrag -     have the system track the mouse movements and
  452. //                            drag the window accordingly.
  453. //
  454.     void TApplication::DoDrag( void )
  455.     {
  456.         DragWindow( fWhichWindow, fTheEvent.where, &qd.screenBits.bounds );
  457.         
  458.     }  /* TApplication::DoDrag */
  459.  
  460.  
  461. //-----------------------------------------------------------------------
  462. // TApplication::DoGoAway -     a mousedown event occurred in the go away region
  463. //                                of the active window; continue tracking it. If
  464. //                                the mouse is released in the region, then close
  465. //                                the window.
  466. //
  467.     void TApplication::DoGoAway( void )
  468.     {
  469.         if ( TrackGoAway( fWhichWindow, fTheEvent.where ))            // was the mouse released in the goAway region?
  470.         {                                                            // yes, but is the window ours?
  471.             if ( fCurDoc != nil )
  472.             {                                                        // it is our window, let's close it
  473.                 fDocList->RemoveDoc( fCurDoc );
  474.                 fCurDoc->DoClose();
  475.             }
  476.             else                                                    // no, the window must belong to the system, let them handle it
  477.                 CloseDeskAcc(((WindowPeek) fWhichWindow )->windowKind );
  478.                 
  479.             // make sure our current document/window references are valid
  480.                 if ( fWhichWindow != nil )                            // does an active window remain? 
  481.                 {
  482.                     fCurDoc = fDocList->FindDoc( fWhichWindow );    // yes, update the current document pointer
  483.                     SetPort( fWhichWindow );                        // be sure to make future drawings to the new window
  484.                 }
  485.                 else
  486.                     fCurDoc = nil;                                    // no active window remains
  487.         }
  488.     }  /* TApplication::DoGoAway */
  489.  
  490.  
  491. //-----------------------------------------------------------------------
  492. // TApplication::TrapAvailable -     Check and see if the trap exists. 
  493. //
  494. /****************
  495.  *    TrapAvailable
  496.  *        drawn from Inside Mac VI, this is a distillation of the 27 different
  497.  *        TrapAvailable routines that Apple provides in their sample code.
  498.  *        Note that this routine is PPC-ready, since it does NOT use GetTrapAddress.
  499.  ********************************************************************************/
  500.     Boolean TApplication::TrapAvailable(short theTrap)
  501.     {
  502.     TrapType        theTrapType;
  503.     
  504.     /* Determine the trap type based on the trap word */
  505.     if ((theTrap & 0x0800) != 0)
  506.         theTrapType = ToolTrap;
  507.     else
  508.         theTrapType = OSTrap;
  509.  
  510.     /* Different versions of the system have different numbers of toolbox traps. */
  511.     if (theTrapType == ToolTrap)
  512.     {
  513.         short            numToolboxTraps;
  514.         theTrap = theTrap & 0x07ff;
  515.         if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xaa6e, ToolTrap))
  516.             numToolboxTraps = 0x0200;
  517.         else
  518.             numToolboxTraps = 0x0400;
  519.         if (theTrap >= numToolboxTraps)
  520.             theTrap = _Unimplemented;
  521.     }
  522.  
  523.     return NGetTrapAddress(theTrap, theTrapType) != 
  524.                 NGetTrapAddress(_Unimplemented, ToolTrap);
  525.  
  526.     }  /* TApplication::TrapAvailable */
  527.  
  528.  
  529. //-----------------------------------------------------------------------
  530. // TApplication::AlertUser -     Simple routine to display an alert dialog
  531. //                                using str# resources. Although this routine
  532. //                                exists and is used in this sample, a more
  533. //                                streamlined approach would be to create a
  534. //                                dialog library (or even an object) which
  535. //                                could be linked in. Using such a method,only
  536. //                                one source copy would exist.
  537. //
  538.     void TApplication::AlertUser( short errResID, short errCode )
  539.     {
  540.         Str255 message;
  541.     
  542.         SetCursor( &qd.arrow );
  543.         GetIndString( message, errResID, errCode );
  544.         ParamText( message, (const unsigned char*)"\p",
  545.                             (const unsigned char*)"\p",
  546.                             (const unsigned char*)"\p" );
  547.         (void) Alert( rUserAlert, nil);
  548.         
  549.     }  /* TApplication::AlertUser */
  550.  
  551. //-----------------------------------------------------------------------
  552. // TApplication::BigBadError -     A variation of AlertUser which aborts to
  553. //                                the finder. 
  554. //
  555.     void TApplication::BigBadError(short errResID, short errCode)
  556.     {
  557.         AlertUser( errResID,errCode );
  558.         ExitToShell();
  559.         
  560.     }  /* TApplication::BigBadError */
  561.     
  562. // That's all, folks...
  563.